//
// Created by Functioner on 2022/2/26.
//

#ifndef RDT_SIM_RDT_PROTOCOL_H
#define RDT_SIM_RDT_PROTOCOL_H

#include <iostream>
#include <vector>
#include <set>
#include <list>
#include <map>

#include "rdt_struct.h"

namespace RDTProtocol {
    // Constants
    const int WindowSize = 30;
    const int SerialSize = 64;
    const double TimerInterval = 1;
    const int MaximumDataSize = RDT_PKTSIZE - 2 - sizeof(uint32_t);
    const int CRC32_Key = 0x04C11DB7;

    const char AckString[] = "ack";

    // Global
    extern unsigned int CRC_32_Table[256];

    // Receiver
    extern std::vector<std::pair<bool, std::string>> receiverSaved;
    extern size_t receiverLeft;

    // Sender
    extern std::list<std::string> senderQueue;
    extern std::vector<std::pair<bool, std::string>> senderSaved;
    extern size_t senderLeft;
    extern size_t senderRight;

    // Timers
    extern std::map<int, int> activeTimers;

    void startTimer(int id);

    void killTimer(int id);

    void onTimer();

    // Encoder and decoders
    uint32_t CRC32_Verify(const std::string &data);

    std::string EncodeMessage(const std::string &data, int index);

    std::string DecodeMessage(const std::string &data, int &index);

    // Sender
    void SendByIndex(int index);

    void ReceiveAcknowledge(const std::string &data);

    void FillSenderWindow();

    bool WithinSenderWindow(int index);

    // Receiver
    void ReceiveMessage(const std::string &data);

    void SendAcknowledge(int index);

    void ReportMessage(const std::string &data);

    bool WithinReceiverWindow(int index);

    // Initialize
    void GenerateCRC32_Table();

    void SenderInit();

    void ReceiverInit();
};


#endif //RDT_SIM_RDT_PROTOCOL_H
